##############################################################
# Makefile for C/C++ project 
# Author: Bob <bob.chen.email@qq.com>
# Date: 2017-05-23 
# Note：Usually, we add Makefile in source file directory
###############################################################
#### set target name
TARGET_NAME = pthread_cond

#### set compile config file path and file name, 'compile.cfg' for default file name
COMPILE_CONFIG_FILE_PATH = ../../
COMPILE_CONFIG_FILE_NAME = compile.cfg

#### set target type: shared, static or exe 
TARGET_TYPE = exe 
#TARGET_TYPE = shared
#TARGET_TYPE = static

#### set output path
OUTPUT_PATH := ../../output

#### set source file path, default ./
SOURCE_FILE_PATH := ./ 

#### set include file path, such as -I./dir1 -I../dir2, separated by space 
INCLUDE_FILE_PATH := 

#### add c files or cpp files, empty for search c files in source file path automatily 
C_SRCS := 

CPP_SRCS :=

#### add exclude c files or cpp files
EXCLUDE_C_SRCS := 

EXCLUDE_CPP_SRCS := 

#### set library path, such as -L./dir1 -L../third_party/lib, separeted by space
LIBRARY_PATH := -L../../output

#### add libs, such as -lhello -lpthread, separated by space
LIBS := -lpthread

#### set compile flag: debug/Debug, release/Release
COMPILE_FLAG = debug
#COMPILE_FLAG = Debug
#COMPILE_FLAG = release
#COMPILE_FLAG = Release

#### set compiler, such as gcc, g++, arm-hisiv300-linux-gcc, arm-hisiv400-linux-gcc, arm-hisiv400-linux-g++,
#### if TARGET_COMPILER has set in CompileConfig file, just ignore this variable
#COMPILER = gcc
#COMPILER = arm-hisiv300-linux-gcc
#COMPILER = arm-hisiv400-linux-gcc
#COMPILER = arm-hisiv300-linux-g++
#COMPILER = arm-hisiv400-linux-g++

#### flags in makefile, you can add more flags, such as -std=c++11, separated by space
DEBUG_FLAG = -g -Wall -c
RELEASE_FLAG = -Wall -c


########################### do not modify the following items ####################################
ARCH := $(shell uname -m)
ARCH_BIT64 := x86_64

#### get current work dir
CUR_DIR := $(shell pwd)

#### save original compiler
ORIGINAL_COMPILER := $(COMPILER)

#### set OBJ file and final output file path 
OBJ_FILE_PATH := $(OUTPUT_PATH)/$(TARGET_NAME)_obj/
FINAL_OUTPUT_PATH := $(OUTPUT_PATH)/

#### list all dirs
SUB_DIRS := $(shell find $(SOURCE_FILE_PATH) -type d)

#### filter out exclude c files and cpp files
#C_SRCS := $(wildcard *.c)
ifeq ($(C_SRCS),)
C_SRCS := $(shell find $(SOURCE_FILE_PATH) -name "*.c")
endif

ifeq ($(CPP_SRCS),)
CPP_SRCS := $(shell find $(SOURCE_FILE_PATH) -name "*.cpp")
endif

ORGINAL_C_SRCS := $(C_SRCS)
ORGINAL_CPP_SRCS := $(CPP_SRCS)
C_SRCS := $(filter-out $(strip $(EXCLUDE_C_SRCS)), $(C_SRCS))
CPP_SRCS := $(filter-out $(strip $(EXCLUDE_CPP_SRCS)), $(CPP_SRCS))

#### prepare object files
#OBJS := $(CPP_SRCS:%.cpp=$(FINAL_OUTPUT_PATH)%.o)
#OBJS += $(C_SRCS:%.c=$(FINAL_OUTPUT_PATH)%.o)
OBJS := $(CPP_SRCS:%.cpp=$(OBJ_FILE_PATH)%.o)
OBJS += $(C_SRCS:%.c=$(OBJ_FILE_PATH)%.o)
#CPP_SRCS += $(C_SRCS)

#### rename command
RM := rm -rf
MOVE := mv
OUT := -o
MKDIR := mkdir -p

RUN_LINK_PATH := -rpath-link=./
RUN_PATH := -Wl,-rpath=./


#### check TARGET_TYPE whether set or not, if set whether use exe, static or shared
ifeq ($(strip $(TARGET_TYPE)),)
     $(error "*ERROR* variable 'TARGET_TYPE' has not set in Makefile, use exe, static or shared")
else
  ifneq ($(strip $(TARGET_TYPE)), $(filter $(strip $(TARGET_TYPE)), exe static shared))
     $(error "*ERROR* variable 'TARGET_TYPE' set error in Makefile, use exe, static or shared")
  endif
endif


#### if CompilConfig file exist, get target compiler from CompileConfig file
ifneq ($(strip $(COMPILE_CONFIG_FILE_PATH)),)
     TARGET_COMPILER_PTAH := $(wildcard $(COMPILE_CONFIG_FILE_PATH)$(COMPILE_CONFIG_FILE_NAME))
     ifneq ($(strip $(TARGET_COMPILER_PTAH)),)
         include $(TARGET_COMPILER_PTAH)
         COMPILER := $(strip $(TARGET_COMPILER))
         INCLUDE_FILE_PATH += $(COMMON_INCLUDE_PATH)
         LIBRARY_PATH += $(COMMON_LIB_PATH)
         LIBS += $(COMMON_LIBS)
     endif
endif


#### check COMPILER whether empty or not
ifeq ($(strip $(COMPILER)),)
     COMPILER := $(ORIGINAL_COMPILER)
     ifeq ($(strip $(COMPILER)),)
         $(error "*ERROR* variable 'COMPILER' has not set, you'd better set TARGET_COMPILER in file compiler.cfg")
     endif
endif


#### check COMPILE_FLAG whether set or not, if set whether use debug/Debug or release/Release
ifeq ($(strip $(COMPILE_FLAG)),)
     $(error "*ERROR* variable 'COMPILE_FLAG' has not set in Makefile, use debug/Debug or release/Release")
else
  ifneq ($(strip $(COMPILE_FLAG)), $(filter $(strip $(COMPILE_FLAG)), debug Debug release Release))
     $(error "*ERROR* variable 'COMPILE_FLAG' has not set in Makefile, use debug/Debug or release/Release")
  endif
endif


#### check variable DEBUG_FLAG  and RELEASE_FLAG 
ifeq ($(strip $(DEBUG_FLAG)),)
     $(warning "*ERROR* variable 'DEBUG_FLAG' has not set in Makefile")
endif

ifeq ($(strip $(RELEASE_FLAG)),)
     $(warning "*ERROR* variable 'RELEASE_FLAG' has not set in Makefile")
endif


#### set compile and link type, default for exe
ifeq ($(strip $(TARGET_TYPE)),exe)
    COMPILE_TYPE = $(COMPILER)
    LINK_TYPE = $(COMPILER) -Wall
    LINK_PARAMTER = -o
endif

ifeq ($(strip $(COMPILE_FLAG)), $(filter $(strip $(COMPILE_FLAG)), debug Debug))
   CFLAGS := $(DEBUG_FLAG)
   COMPILE_TYPE = $(COMPILER)
   LINK_TYPE = $(COMPILER) -Wall -g
   LINK_PARAMTER = -o
else
   CFLAGS := $(RELEASE_FLAG)
endif


#### for shared or static library
ifeq ($(strip $(TARGET_TYPE)),shared)
    COMPILE_TYPE = $(COMPILER) -fPIC
    LINK_TYPE = $(COMPILER) -shared -fPIC
    TARGET_NAME := lib$(TARGET_NAME).so
endif

ifeq ($(strip $(TARGET_TYPE)),static)
    COMPILE_TYPE = $(COMPILER) 
    LINK_TYPE = ar rc
    TARGET_NAME := lib$(TARGET_NAME).a
    LINK_PARAMTER =
    ifeq ($(strip $(ARCH)), $(ARCH_BIT64))
        COMPILE_TYPE += -fPIC
    endif
endif


.PHONY : all clean print realclean 
#### all target 
all : CreateDir $(FINAL_OUTPUT_PATH)$(TARGET_NAME) 


#CreateDir : 
#	-$(MKDIR) $(FINAL_OUTPUT_PATH);
#	for dirs in $(SUB_DIRS); do $(MKDIR) $(FINAL_OUTPUT_PATH)$${dirs}; done;
#	@echo ' '


CreateDir : 
	-$(MKDIR) $(OBJ_FILE_PATH);
	for dirs in $(SUB_DIRS); do $(MKDIR) $(OBJ_FILE_PATH)$${dirs}; done;
	@echo ' '

#### tool invocations
$(FINAL_OUTPUT_PATH)$(TARGET_NAME):$(OBJS)
	@echo 'Building target: $@'
	$(LINK_TYPE) $(LINK_PARAMTER) $@ $^ $(LIBRARY_PATH) $(LIBS)
	@echo 'Finished building target: $@'
	@echo ' '


#$(FINAL_OUTPUT_PATH)%o:./%cpp
$(OBJ_FILE_PATH)%o:./%cpp
	@echo 'Building file: $<'
	$(COMPILE_TYPE) $(CFLAGS) $< $(OUT) $@ $(INCLUDE_FILE_PATH) 
	@echo 'Finished building file: $<'
	@echo ''


#$(FINAL_OUTPUT_PATH)%o:./%c
$(OBJ_FILE_PATH)%o:./%c
	@echo 'Building file: $<'
	$(COMPILE_TYPE) $(CFLAGS) $< $(OUT) $@ $(INCLUDE_FILE_PATH)
	@echo 'Finished building file: $<'
	@echo ''

clean :
	$(RM) $(OBJS)
	$(RM) $(FINAL_OUTPUT_PATH)$(TARGET_NAME)
	@echo ' '

print:
	@echo "Current work dir:$(CUR_DIR)"
	@echo 'ORGINAL_C_SRCS:' $(ORGINAL_C_SRCS)
	@echo 'EXCLUDE_C_SRCS:' $(EXCLUDE_C_SRCS)
	@echo 'C_SRCS:' $(C_SRCS)
	@echo 'ORGINAL_CPP_SRCS:' $(ORGINAL_CPP_SRCS)
	@echo 'EXCLUDE_CPP_SRCS:' $(EXCLUDE_CPP_SRCS)
	@echo 'CPP_SRCS:' $(CPP_SRCS)
	@echo 'OBJS:' $(OBJS)
	@echo 'FinalOutputPath:' $(FINAL_OUTPUT_PATH)
	@echo 'TargetName:' $(TARGET_NAME)
	@echo 'ORIGINAL_COMPILER:' $(ORIGINAL_COMPILER)
	@echo 'COMPILER:' $(COMPILER)
	@echo 'INCLUDE_FILE_PATH:' $(INCLUDE_FILE_PATH) 
	@echo 'LIBS:' $(LIBS) 
	@echo 'LIBRARY_PATH:' $(LIBRARY_PATH) 
	@echo 'COMPILE_CONFIG_FILE_PATH:' $(COMPILE_CONFIG_FILE_PATH) 
	@echo 'COMPILE_CONFIG_FILE_NAME:' $(COMPILE_CONFIG_FILE_NAME) 
	@echo 'ARCH:' $(ARCH) 
	@echo ' ' 
	
realclean :
	$(RM) $(FINAL_OUTPUT_PATH)
	@echo ' '
